﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using TTGame;
using System;

/*
 * DataInfos
 * 一些小数据结构
 *
 *
 * 依赖：
 *
 * ！不写重复代码！
 * @author TTun
 * @date 7/28/2017 2:50:35 PM
 */
namespace TTGameEngine {

public enum MoveType {
    MoveDir,
    MoveFollowObj,
    MoveTargetPos,
}


//除了OtherForceMove，其他的MoveID只能有一个存在。
public enum MoveID {
    WalkOrRun,  //正常行走
    Knockback,  //击退
    Rush,       //冲锋
    OtherForceMove, //其他强制位移，可多个
}



/// <summary>
/// 移动信息
///
/// 用于描述对象移动的信息。
/// 移动方式、移动参数
///
/// </summary>
[System.Serializable]
public class MoveInfo {
    public MoveID moveID = MoveID.WalkOrRun;
    public MoveType moveType = MoveType.MoveDir;
    public Vector3 moveDir;
    public Transform moveFollowTF;
    public Vector3 moveTargetPos;
    public float maxMoveDistance;   // 0 表示不限制距离
    public float maxMoveTime;       // 0 表示不限制时间
    [WriteEnabled]
    public float moveSpeed;
    public bool isEnable = false;
    [Tooltip("因碰撞排斥导致的移动方向偏移")]
    public Vector3 colliderOffsetDir = Vector3.zero;


    [ReadOnly]
    public float lastMoveDis;
    [ReadOnly]
    public Vector3 lastMoveDir;
    Quaternion lastDirQ = Quaternion.identity;
    bool isFirstSetup = true;

    public virtual void StopMove() {
        Reset();
        isEnable = false;
        lastMoveDis = 0;
        lastMoveDir = Vector3.zero;
        lastDirQ = Quaternion.identity;
    }

    public bool IsMoving(){
        return isEnable;
    }

    public virtual void Reset() {
        moveID = MoveID.WalkOrRun;
        moveType = MoveType.MoveDir;
        moveDir = Vector3.zero;
        moveFollowTF = null;
        moveTargetPos = Vector3.zero;
        maxMoveDistance = 0f;
        maxMoveTime = 0;
        isEnable = true;
        isFirstSetup = true;
    }

    public void SetMoveDir(Vector3 dir) {
        moveType = MoveType.MoveDir;
        moveDir = dir.normalized;
        isFirstSetup = true;
    }

    public void SetMovePos(Vector3 Pos) {
        moveType = MoveType.MoveTargetPos;
        moveTargetPos = Pos;
        isFirstSetup = true;
    }

    public void SetMoveFollow(Transform followObjTF) {
        moveType = MoveType.MoveFollowObj;
        moveFollowTF = followObjTF;
        moveTargetPos = followObjTF.position;
        isFirstSetup = true;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="dt"></param>
    /// <param name="posNow"></param>
    /// <param name="posNext"></param>
    /// <returns>是否移动结束。true：移动结束。</returns>
    public virtual bool ObjMoveStep(float dt, Vector3 posNow, out Vector3 posNext) {
        Vector3 moveDirection = Vector3.zero;
        Vector3 tmpMoveTargetPos = Vector3.zero;
        bool moveType_Pos = false;
        bool isMoveDisOver = false;
        bool isMoveArrive = false;
        bool isTimeOver = false;


        posNext = posNow;
        switch(moveType) {
            case MoveType.MoveDir:
                moveDirection = moveDir;
                moveType_Pos = false;
                break;
            case MoveType.MoveFollowObj:
                if(moveFollowTF != null) {
                    tmpMoveTargetPos = moveFollowTF.position;
                    moveTargetPos = tmpMoveTargetPos;
                    moveDirection = tmpMoveTargetPos - posNow;
                } else {
                    tmpMoveTargetPos = moveTargetPos;
                }
                moveType_Pos = true;
                break;
            case MoveType.MoveTargetPos:
                tmpMoveTargetPos = moveTargetPos;
                moveDirection = tmpMoveTargetPos - posNow; ;
                moveType_Pos = true;
                break;
        }

        if(isMoveArrive == false) {
            //检测时间
            if(maxMoveTime > 0) {
                if(maxMoveTime < dt) {
                    dt = maxMoveTime;
                    isTimeOver = true;
                    maxMoveTime = -1f;
                } else {
                    maxMoveTime -= dt;
                }
            }


            if(isFirstSetup) {

                isFirstSetup = false;
                lastDirQ = Tools.ForwardToRotate(moveDirection);
            }

            float stepMoveDis = moveSpeed * dt;
            lastMoveDis = stepMoveDis;
            moveDirection.Normalize();
            if(moveType != MoveType.MoveDir && colliderOffsetDir.IsZero() == false) {
                moveDirection = moveDirection + colliderOffsetDir;
                moveDirection.y = 0;
                //对移动方向做平滑处理。
                lastDirQ = Quaternion.RotateTowards(Quaternion.LookRotation(lastMoveDir), Quaternion.LookRotation(moveDirection), DebugSetting.Self.ColliderRotationSpeed * dt);
                moveDirection = Tools.RotateToForward(lastDirQ);
                moveDirection.Normalize();
            }

            //检测最大距离
            if(maxMoveDistance > 0) {
                if(maxMoveDistance < stepMoveDis) {
                    stepMoveDis = maxMoveDistance;
                    isMoveDisOver = true;
                    maxMoveDistance = -1f;
                } else {
                    maxMoveDistance -= stepMoveDis;
                }
            }
            if(moveType_Pos && tmpMoveTargetPos.distanceLess(posNow, stepMoveDis)) {
                posNext = tmpMoveTargetPos;
                isMoveArrive = true;
            } else {
                posNext = posNow + (moveDirection * stepMoveDis);
                isMoveArrive = false;
            }
        } else {
            posNext = posNow;
        }

        if(isMoveArrive || isMoveDisOver || isTimeOver) {
            isEnable = false;
        }
        lastMoveDir = moveDirection;
        //isMoveEnd
        return !isEnable;
    }

    //强制位移信息产生的位移。不考虑是否到达点。
    public Vector3 ForceStep(float dt, Vector3 posNow) {
        Vector3 tmpMoveTargetPos = Vector3.zero;
        Vector3 moveDirection = Vector3.zero;
        Vector3 moveStep;
        switch(moveType) {
            case MoveType.MoveDir:
                moveDirection = moveDir;
                break;
            case MoveType.MoveFollowObj:
                tmpMoveTargetPos = moveFollowTF.position;
                moveDirection = (tmpMoveTargetPos - posNow).normalized;
                break;
            case MoveType.MoveTargetPos:
                tmpMoveTargetPos = moveTargetPos;
                moveDirection = (tmpMoveTargetPos - posNow).normalized;
                break;
        }

        moveStep = moveDirection * (moveSpeed * dt);

        return moveStep;
    }

    public virtual MoveInfo Copy() {
        return new MoveInfo().CopyWith(this);
    }

    public virtual MoveInfo CopyWith(MoveInfo moveInfo) {
        moveID = moveInfo.moveID;
        moveType = moveInfo.moveType;
        moveDir = moveInfo.moveDir;
        moveFollowTF = moveInfo.moveFollowTF;
        moveTargetPos = moveInfo.moveTargetPos;
        maxMoveDistance = moveInfo.maxMoveDistance;
        maxMoveTime = moveInfo.maxMoveTime;
        moveSpeed = moveInfo.moveSpeed;
        isEnable = moveInfo.isEnable;
        return this;
    }
}

/// <summary>
/// 抛物线移动方式参数。
/// </summary>
[System.Serializable]
public class ParabolaMoveInfo : MoveInfo {

    [SerializeField, WriteEnabled]
    float durationTime = 2f;
    [SerializeField, WriteEnabled]
    float ParamHeight = 12f;
    Vector3 _startPos;
    Vector3 _endPos;
    Vector3 _c1;
    bool isStartMove = false;
    float t_runningTime = 0f;

    public override void Reset() {
        base.Reset();
        t_runningTime = 0;
        isStartMove = false;
    }

    void initMove(Vector3 posStart) {
        Vector3 tmpMoveTargetPos = Vector3.zero;
        switch(moveType) {
            case MoveType.MoveDir:
                //不支持
                break;
            case MoveType.MoveFollowObj:
                //追踪对象，暂不实现
                break;
            case MoveType.MoveTargetPos:
                //固定坐标
                tmpMoveTargetPos = moveTargetPos;
                break;
        }
        _startPos = posStart;
        _endPos = tmpMoveTargetPos;
        _c1 = (_startPos + _endPos) / 2;
        _c1.y += ParamHeight;

        t_runningTime = 0;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="dt"></param>
    /// <param name="posNow"></param>
    /// <param name="posNext"></param>
    /// <returns>是否移动结束。true：移动结束。</returns>
    public override bool ObjMoveStep(float dt, Vector3 posNow, out Vector3 posNext) {
        bool isTimeOver = false;
        bool isMoveArrive = false;
        switch(moveType) {
            case MoveType.MoveDir:
                //不支持
                DebugUtil.LogWarningFormat("抛物线-暂不支持移动方向。强制默认固定坐标");
                moveType = MoveType.MoveTargetPos;
                break;
            case MoveType.MoveFollowObj:
                //追踪对象，暂不实现
                DebugUtil.LogWarningFormat("抛物线-暂不支持跟随对象。强制默认固定坐标");
                moveType = MoveType.MoveTargetPos;
                break;
            case MoveType.MoveTargetPos:
                //固定坐标
                break;
        }

        if(isStartMove == false) {
            initMove(posNow);
            isStartMove = true;
        }

        //检测时间
        if(maxMoveTime > 0) {
            if(maxMoveTime < dt) {
                dt = maxMoveTime;
                isTimeOver = true;
                maxMoveTime = -1f;
            } else {
                maxMoveTime -= dt;
            }
        }

        t_runningTime += dt;
        float inp = 0f;
        if(durationTime <= 0) {
            inp = 1f;
        } else {
            inp = t_runningTime / durationTime;
        }
        if(inp >= 1) {
            inp = 1;
            isMoveArrive = true;
        }
        posNext = getBezierInp(inp);

        if(isMoveArrive || isTimeOver) {
            isEnable = false;
        }
        return !isEnable;
    }
    Vector3 getBezierInp(float t) {
        return (1 - t) * (1 - t) * _startPos + 2 * t * (1 - t) * _c1 + t * t * _endPos;
    }

    public override MoveInfo Copy() {
        return new ParabolaMoveInfo().CopyWith(this);
    }

    public override MoveInfo CopyWith(MoveInfo moveInfo) {
        ParabolaMoveInfo typeMoveInfo = moveInfo as ParabolaMoveInfo;
        durationTime = typeMoveInfo.durationTime;
        return this;
    }
}

public class MoveResult {
    public Vector3 nextPos;
    public Vector3 moveDir;
}

/// <summary>
/// 碰撞信息
///
/// 整合几种不同碰撞框的信息
/// </summary>
[System.Serializable]
public class ColliderInfo {
    //形状     参数
    //圆形    半径
    //矩形    长宽
    //扇形    半径、角度
    //射线    射线长度
    public float m_radius;
    public float m_angle;
    public Vector3 m_rectSize;
    public Vector3 m_rectCenterOffset;
    [ReadOnly, Tooltip("射线检测长度 = Speed * deltaTime * Factor")]
    public float m_moveSpeed;
    [Tooltip("直线碰撞会用到，默认为1.1")]
    public float m_rayLenFactor = 1.1f;

    public TargetTypeID m_targetType;
    public ColliderShape m_atkShape = ColliderShape.Sphere; //碰撞框形状

    public virtual ColliderInfo Copy() {
        return new ColliderInfo().CopyWith(this);
    }

    public virtual ColliderInfo CopyWith(ColliderInfo obj) {
        m_radius    = obj.m_radius;
        m_angle     = obj.m_angle;
        m_rectSize  = obj.m_rectSize;
        m_rectCenterOffset = obj.m_rectCenterOffset;
        m_targetType = obj.m_targetType;
        m_atkShape  = obj.m_atkShape;
        m_moveSpeed = obj.m_moveSpeed;
        m_rayLenFactor = obj.m_rayLenFactor;

        return this;
    }
}


/// <summary>
/// 弹药袋
/// </summary>
[Serializable]
public class AmmoPouch {
    public int bulletID;
    public int bulletCount;
    //弹匣是无限的，但是还是要换弹的。
    public bool IsInfinitiBullet = false;

    public AmmoPouch(int bulID, int bulCount, bool aIsInfinitiBullet = false) {
        bulletID = bulID;
        bulletCount = bulCount;
        IsInfinitiBullet = aIsInfinitiBullet;
    }

}

}
